#ifndef ANALYSISLOGIC_HPP
#define ANALYSISLOGIC_HPP

#include <QString>
#include <QDateTime>
#include <QJsonObject>
#include <QJsonDocument>
#include <QDebug>
#include <QDir>
#include <QFileInfoList>
#include <QFile>
#include <QtConcurrent>
#include <tinyxml2.h>
#include <QUuid>
#include "store/struct/Reference.hpp"
#include "store/struct/Source.hpp"
#include "store/struct/MergeToAll.hpp"
#include "store/struct/Basic.hpp"
#include "store/struct/Rhythm.hpp"
#include "store/struct/LadderLine.hpp"
#include "analysis/AnalysisXML.hpp"
#include "Utility.hpp"
#include "AnalysisXMLReference.hpp"
#include "AnalysisXMLSource.hpp"

#include <QList>
#include <QVector>
#include <QPair>

// Define the Queries struct
struct Queries {
    int key;
    QString node;
    QPair<int, int> pair;
    QPair<int, int> slot;
};

// 分析逻辑类
class AnalysisLogic {
public:
    /**
     * @brief 导入文件夹并解析 XML，返回合并后的数据列表
     *
     * @param baseDirPath 文件路径 (BeatEditor目录)
     * @param dateStr 可选的日期字符串 (格式: "YYYY-MM-DD"). 如果未提供，则使用当前日期.
     * @return QList<MergeToAll> 合并后的数据列表
     */
    static Basic ImportXML(const QString &baseDirPath, const QString &dateStr = QString(), const int& num = 2) {

        QString dateToUse;
        if (dateStr.isEmpty()) {
            dateToUse = QDate::currentDate().toString("yyyy-MM-dd");
            return {};
            // qDebug() << "No date provided. Using current date:" << dateToUse;
        } else {
            dateToUse = dateStr;
            // qDebug() << "Using provided date:" << dateToUse;
        }

        QList<MergeToAll> mergedData;
        QVector<Queries> queries; // Changed from QMap<int, QVector<QPair<int, int>>> to QVector<Queries>

        QDir baseDir(baseDirPath);
        if (!baseDir.exists()) {
            qDebug() << "Directory not found:" << baseDirPath;
            return {};
        }

        // 找到 BeatEditor.xml
        QString beatEditorXmlPath = baseDir.filePath("BeatEditor.xml");
        if (!QFile::exists(beatEditorXmlPath)) {
            qDebug() << "BeatEditor.xml not found in" << baseDirPath;
            return {};
        }

        // 解析 BeatEditor.xml 以获取 Reference 列表
        QList<Reference> references = parseBeatEditorXml(beatEditorXmlPath);
        // qDebug() << "Parsed" << references.size() << "references from BeatEditor.xml";

        // 遍历 BeatEditor 目录下的子文件夹（例如 "01#2024-12-13"）
        QFileInfoList subFolders = baseDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
        // qDebug() << "Found" << subFolders.size() << "subfolders in" << baseDirPath;

        for (const QFileInfo &folderInfo : subFolders) {
            if (!folderInfo.isDir()) {
                qDebug() << "Skipping non-directory:" << folderInfo.fileName();
                continue;
            }

            QString folderName = folderInfo.fileName();
            QDateTime folderDate = parseFolderDate(folderName);
            if (!folderDate.isValid()) {
                qDebug() << "Invalid folder date in:" << folderName;
                continue;
            }

            // qDebug() << dateStr << folderDate.toString("yyyy-MM-dd") << dateToUse;

            if (!dateStr.isEmpty() && folderDate.toString("yyyy-MM-dd") != dateToUse) {
                // qDebug() << "Skipping folder due to date mismatch:" << folderName;
                continue;
            }

            // qDebug() << "Processing folder:" << folderName << "with date:" << folderDate.toString();

            QString subFolderPath = folderInfo.absoluteFilePath();
            QDir subDir(subFolderPath);

            // // 遍历子文件夹下的子文件夹（例如 "1", "2"）
            // QFileInfoList innerFolders = subDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
            // // qDebug() << "  Found" << innerFolders.size() << "inner folders in" << subFolderPath;

            // 1. 获取所有子文件夹
            QFileInfoList allInnerFolders = subDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);

            // 2. 对文件夹按名称升序（或根据需要按时间等）排序
            std::sort(allInnerFolders.begin(), allInnerFolders.end(), [](const QFileInfo &a, const QFileInfo &b) {
                // 假设子文件夹名都是数字，可用 toInt() 比较
                // 如果文件夹名并非纯数字，请根据实际需求调整比较逻辑
                return a.fileName().toInt() < b.fileName().toInt();
            });

            // 3. 只获取最后两个子文件夹
            QFileInfoList lastTwoFolders;
            if (allInnerFolders.size() > num) {
                lastTwoFolders = allInnerFolders.mid(allInnerFolders.size() - num, num);
            } else {
                // 如果文件夹不足两个，则全部保留
                lastTwoFolders = allInnerFolders;
            }

            for (const QFileInfo &innerFolderInfo : lastTwoFolders) {
                if (!innerFolderInfo.isDir()) {
                    qDebug() << "  Skipping non-directory inner folder:" << innerFolderInfo.fileName();
                    continue;
                }

                QString innerFolderName = innerFolderInfo.fileName();
                bool innerOk = false;
                int subFolderNumber = innerFolderName.toInt(&innerOk);
                if (!innerOk) {
                    qDebug() << "  Invalid subfolder number in:" << innerFolderName;
                    continue;
                }

                // qDebug() << "  Processing inner folder:" << innerFolderName << "with number:" << subFolderNumber;

                QString innerFolderPath = innerFolderInfo.absoluteFilePath();
                QDir innerDir(innerFolderPath);

                // 查找所有 .xml 文件（例如 "14.xml"）
                QStringList filters;
                filters << "*.xml";
                QFileInfoList xmlFiles = innerDir.entryInfoList(filters, QDir::Files);
                // qDebug() << "    Found" << xmlFiles.size() << ".xml files in" << innerFolderPath;

                for (const QFileInfo &xmlFileInfo : xmlFiles) {
                    QString fileName = xmlFileInfo.fileName();
                    int fileNumber = parseFileNumber(fileName);
                    if (fileNumber < 0) {
                        qDebug() << "    Invalid file number in:" << fileName;
                        continue;
                    }

                    QString xmlFilePath = xmlFileInfo.absoluteFilePath();
                    // qDebug() << "    Processing XML file:" << xmlFilePath << "with number:" << fileNumber;

                    // 解析内层 XML 文件以获取 Source 列表
                    QList<Source> sources = parseInnerXml(xmlFilePath);
                    // qDebug() << "      Parsed" << sources.size() << "sources from" << xmlFilePath;

                    // 将 Reference 和 Source 数据合并
                    for (const Reference &ref : references) {
                        // Populate the Queries struct
                        Queries q;
                        q.key = subFolderNumber;
                        q.node = ref.node;
                        q.pair = qMakePair(ref.svalue, ref.evalue);
                        q.slot = qMakePair(ref.sslot.toInt(), ref.eslot.toInt());
                        queries.append(q);

                        for (const Source &src : sources) {
                            if(ref.sboard != src.board && ref.eboard != src.board) continue;
                            if(ref.stype != src.type && ref.etype != src.type) continue;

                            // 创建 MergeToAll 实例
                            MergeToAll merged(ref.node, folderDate, subFolderNumber, fileNumber, ref, src);
                            mergedData.append(merged);

                            // qDebug() << merged.toJson();
                            // qDebug() << ref.node << ref.sname << ref.ename;
                        }
                    }
                }
            }
        }

        return mergedData.size() == 0 ? Basic() : analyzeCombinationsBasic(mergedData.first().duraction,mergedData.last().duraction,printTypeValueCombinations(queries, mergedData), findAllMergeToAll(queries, mergedData));
    }

private:

    /**
        解析组合
     */

    static Basic analyzeCombinationsBasic(const QDateTime &startTime, const QDateTime &endTime,const QList<Rhythm> &rhyhtms, const QList<LadderLine>& ladderLines) {
        Basic basic(startTime, endTime, rhyhtms, ladderLines);
        return basic;
    }

    /**
     * @brief 修改后的 printTypeValueCombinations 函数
     *
     * @param queries QVector<Queries> 结构化的查询数据
     * @param mergedData 合并后的数据列表
     */
    static QList<Rhythm>
    printTypeValueCombinations(const QVector<Queries>& queries,
                               const QList<MergeToAll>& mergedData) {
        QList<Rhythm> rhythms;

        // 遍历每一个 query
        for (const auto& query : queries) {

            // -------------------- 1. 根据 node 筛选 mergeData --------------------
            QList<MergeToAll> filtered;
            for (const auto& data : mergedData) {
                if (data.node == query.node) {
                    filtered.append(data);
                }
            }

            // 如果没有符合的，就不做后面的操作
            if (filtered.isEmpty()) {
                qDebug() << "No matching MergeToAll items found for node:" << query.node;
                continue;
            }

            // -------------------- 2. 以 subFolderNumber 分组 --------------------
            // 这里最好每次 query 都独立地构建 map，而不是在外面定义
            QMap<int, QList<MergeToAll>> groupedBySubFolder;
            for (const auto& item : filtered) {
                groupedBySubFolder[item.subFolderNumber].append(item);
            }

            // 打印当前 query 的信息(可选)
            // qDebug() << "Processing Query with key=" << query.key
            //          << ", pair=" << query.pair
            //          << ", slot=" << query.slot
            //          << ", node=" << query.node;

            // -------------------- 3. 寻找匹配组合 --------------------
            QVector<QPair<int, int>> matchingCombinations =
                                      findMatchingCombinations(groupedBySubFolder,
                                              query.key,
                                              query.node,
                                              query.pair.first,
                                              query.pair.second,
                                              query.slot.first,
                                              query.slot.second);

            // -------------------- 4. 把匹配对 (i, j) 组装为 Rhythm 并打印 --------------------
            // 注意：我们只对 query.key 对应的列表进行处理
            auto it = groupedBySubFolder.find(query.key);
            if (it == groupedBySubFolder.end()) {
                // 说明 subFolder 里没有 key==query.key 的分组
                continue;
            }
            const QList<MergeToAll>& itemList = it.value();

            for (const auto& combo : matchingCombinations) {
                int iIndex = combo.first;
                int jIndex = combo.second;
                if (iIndex >= 0 && iIndex < itemList.size() && jIndex >= 0 && jIndex < itemList.size()) {
                    double diff = calculateTimeDifference(itemList[iIndex].duraction, itemList[jIndex].duraction);

                    Rhythm r(query.key, query.node, itemList[iIndex].duraction, itemList[jIndex].duraction, diff);

                    // qDebug() << r.toJson();
                    rhythms.append(r);
                }
            }

        } // end of for(query)

        return rhythms;
    }


    /**
     * @brief 组合算法函数实现
     *
     * @param mergedData 合并后的数据列表(key -> MergeToAll列表)
     * @param key        当前 key
     * @param node       当前 node
     * @param first      要匹配的 slotsz[A]
     * @param second     要匹配的 slotsz[B]
     * @param sslot      slotsz里第一个下标位置
     * @param eslot      slotsz里第二个下标位置
     * @return           符合条件的组合索引 (i, j)
     */
    static QVector<QPair<int, int>>
                                 findMatchingCombinations(const QMap<int, QList<MergeToAll>>& mergedData,
                                         const int& key,
                                         const QString& node,
                                         const int& first,
                                         const int& second,
                                         const int sslot,
    const int eslot) {
        QVector<QPair<int, int>> combinations;

        // 查找 key 对应的列表，不存在则返回空
        auto it = mergedData.find(key);
        if (it == mergedData.end()) {
            return combinations;
        }

        const QList<MergeToAll>& itemList = it.value();

        int i = 0;
        while (i < itemList.size()) {
            const auto &currentItem = itemList[i];

            // 检查 sslot 是否在范围内
            if (sslot < 0 || sslot >= currentItem.slotsz.size()) {
                i++;
                continue;
            }

            // 判断当前 slotsz[sslot] 是否为 first
            if (currentItem.slotsz[sslot] == first) {
                bool found = false;
                // 内层循环找 B
                for (int j = i + 1; j < itemList.size(); ++j) {
                    const auto &nextItem = itemList[j];

                    // 检查 eslot 范围
                    if (eslot < 0 || eslot >= nextItem.slotsz.size()) {
                        continue;
                    }

                    // 判断 slotsz[eslot] 是否为 second
                    if (nextItem.slotsz[eslot] == second) {
                        // 找到匹配对
                        combinations.append(qMakePair(i, j));

                        // 跳过到 j+1 继续搜索
                        i = j + 1;
                        found = true;
                        break;
                    }
                }
                // 如果没找到 B，就 i++
                if (!found) {
                    i++;
                }
            } else {
                i++;
            }
        }

        return combinations;
    }





    /**
     * @brief 获取所有数据，并聚合分组
     *
     * @param mergedData 合并后的数据列表
     * @return QList<Scatter> 按 node 分组后的数据
     */
    static QList<LadderLine> findAllMergeToAll(const QVector<Queries>& queries, const QList<MergeToAll>& mergedData) {
        // 如果 mergedData 为空，就直接返回
        if (mergedData.isEmpty()) {
            qDebug() << "mergedData is empty!";
            return {};
        }

        // 1. 找到 mergedData 中最大的 subFolderNumber
        int maxSubFolderNumber = -1;
        for (const auto &m : mergedData) {
            if (m.subFolderNumber > maxSubFolderNumber) {
                maxSubFolderNumber = m.subFolderNumber;
            }
        }

        // 2. 过滤出所有 subFolderNumber == maxSubFolderNumber 的数据
        QList<MergeToAll> filteredMergedData;
        for (const auto &m : mergedData) {
            if (m.subFolderNumber == maxSubFolderNumber) {
                filteredMergedData << m;
            }
        }

        // 以下是原先的逻辑，只不过将数据源替换为 filteredMergedData
        QList<LadderLine> ladderLines;
        QDateTime firstTime = filteredMergedData.first().duraction;

        // 遍历过滤后的 mergedData，将其转换成 LadderLine
        for (const auto &m : filteredMergedData) {
            LadderLine sline;
            LadderLine eline;
            // qDebug() << m.toJson();

            sline.subFolderNumber = m.subFolderNumber;
            sline.node         = m.sname;
            sline.slotval      = m.slotsz[m.sslot.toInt()];
            sline.triggerTime  = m.duraction;
            sline.trigger      = calculateTimeOffsetInSeconds(firstTime, m.duraction);

            eline.subFolderNumber = m.subFolderNumber;
            eline.node         = m.ename;
            eline.slotval      = m.slotsz[m.eslot.toInt()];
            eline.triggerTime  = m.duraction;
            eline.trigger      = calculateTimeOffsetInSeconds(firstTime, m.duraction);

            // 添加到返回列表
            ladderLines.append(sline);
            ladderLines.append(eline);
        }

        // 根据 subFolderNumber 分组
        QMap<int, QList<LadderLine>> groupedLines;
        for (const auto &line : ladderLines) {
            groupedLines[line.subFolderNumber].append(line);
        }

        // 如果分组为空，直接返回
        if (groupedLines.isEmpty()) {
            qDebug() << "没有任何分组数据。";
            return {};
        }

        // 因为我们已经手动过滤出最大的 subFolderNumber，所以这里的分组可能就只有一个键
        // 当然你也可以继续使用原本的逻辑去获取 '最后一个分组'：
        int lastKey = groupedLines.keys().last();
        QList<LadderLine> lastGroup = groupedLines.value(lastKey);

        // 对最后一个分组先按 node 升序，再按 trigger 升序
        std::sort(lastGroup.begin(), lastGroup.end(), [](const LadderLine &a, const LadderLine &b) {
            if (a.node != b.node)
                return a.node < b.node;  // 首先按 node 升序
            return a.trigger < b.trigger; // node 相同则按 trigger 升序
        });

        // 将排序后的分组赋给 ladderLines
        ladderLines.clear();
        ladderLines = lastGroup;

        // qDebug() << "\n更新后的 ladderLines:";
        // for (const auto &line : ladderLines) {
        //     qDebug() << "  " << line.toJson();
        // }

        return ladderLines;
    }




    /**
     * @brief 解析 BeatEditor.xml 文件，获取 Reference 列表
     *
     * @param filePath BeatEditor.xml 文件路径
     * @return QList<Reference> Reference 列表
     */
    /**
     * @brief 解析 BeatEditor.xml 文件，获取 Reference 列表
     *
     * @param filePath BeatEditor.xml 文件路径
     * @return QList<Reference> Reference 列表
     */
    static QList<Reference> parseBeatEditorXml(const QString &filePath) {
        QList<Reference> references;

        // 用 Qt 的 QFile 来读取文件，避免编码问题
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            qDebug() << "Failed to open file for reading:" << filePath;
            return references;
        }
        QByteArray xmlData = file.readAll();
        file.close();

        tinyxml2::XMLDocument doc;
        // 直接解析内存数据（避免使用 LoadFile(filePath)）
        if (doc.Parse(xmlData.constData()) != tinyxml2::XML_SUCCESS) {
            qDebug() << "Failed to parse BeatEditor.xml content:" << filePath;
            return references;
        }

        tinyxml2::XMLElement *root = doc.RootElement();
        if (!root) {
            qDebug() << "No root element in BeatEditor.xml";
            return references;
        }

        for (tinyxml2::XMLElement* nodeElem = root->FirstChildElement("node");
                nodeElem;
                nodeElem = nodeElem->NextSiblingElement("node")) {
            Reference ref = AnalysisXML<Reference>::fromXMLElement(nodeElem);
            references.append(ref);
        }

        return references;
    }


    /**
     * @brief 解析内层 XML 文件，获取 Source 列表
     *
     * @param filePath 内层 XML 文件路径
     * @return QList<Source> Source 列表
     */
    static QList<Source> parseInnerXml(const QString &filePath) {
        QList<Source> sources;

        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            qDebug() << "Failed to open file for reading:" << filePath;
            return sources;
        }
        QByteArray xmlData = file.readAll();
        file.close();

        tinyxml2::XMLDocument doc;
        if (doc.Parse(xmlData.constData()) != tinyxml2::XML_SUCCESS) {
            qDebug() << "Failed to parse inner xml:" << filePath;
            return sources;
        }

        tinyxml2::XMLElement* root = doc.RootElement();
        if (!root) {
            qDebug() << "No root element in" << filePath;
            return sources;
        }

        for (tinyxml2::XMLElement* nodeElem = root->FirstChildElement("node");
                nodeElem;
                nodeElem = nodeElem->NextSiblingElement("node")) {
            Source src = AnalysisXML<Source>::fromXMLElement(nodeElem);
            sources.append(src);
        }

        return sources;
    }

};

#endif // ANALYSISLOGIC_HPP
